#ifndef XEVA
#define XEVA

#include "VMPFocus.hpp"
#include "operations.hpp"

//	Operation x()
//formula:
//(:higher:|:same:):blank:?\(
//    ((:blank:?(:higher:|:same:|:lower:):blank:?){0,1}    //Just happened parameter once or none.
//    |(:blank:?(:higher:|:same:|:lower:):blank:?)(,:blank:?(:higher:|:same:|:lower:):blank:?)?)
//\)
//PreLining:
cText TEXT_XEVA="x()";

void funOpXEPreL(ListIdentity* what){
	fPreL_priority(&TEXT_XEVA,what);
}

//FoundIdentity:
void funOpXEFI(ptrIdentity what){
	what->Identifier=&TEXT_PRIORITY_SAME;
}

//PostLining:
 
//MkTree:

//Evaluate:
void preLocal(ptrRETNode nRET,ptrDough call){
	//this, that pointer:
	nRET->Locals.push("this",call);
	nRET->Locals.push("that",nRET->Dough);
}

void paramInit(ptrRETNode nRET, ptrRETNode retnode, ptrDough call, ptrParsedElement pe){//pe:1st is called, 2nd,3rd,etc are params.
	//params:
	//init params list.
	ptrDough Arguments;
	Arguments=CreateDough();
	ptrdArray vt		  =new dArray();
	Arguments->Extended->push(EXT_ARRAY,(void*)vt);
	nRET->Locals.push("Arguments",Arguments); //so called dough can use Arguments[0], such to visit params.
	//has a param name list?
	vt->push(0,call);
	ptrParams	tmp=(ptrParams)(call->Extended->search(EXT_PARAM));
	if (tmp)//yes
		for (int i=1; i<pe->SubElements.length(); ++i){
			ptrDough param=pe->SubElements[i]->Operation->onEvaluate(
					retnode,pe->SubElements[i],NULL
				).dough;
			if (i-1<tmp->length())
				nRET->Locals.push((*tmp)[i-1],param);
			vt->push(i,param);
		}
	else//no param list, just build an argument array.
		for (int i=1; i<pe->SubElements.length(); ++i){
			ptrDough param=pe->SubElements[i]->Operation->onEvaluate(
					retnode,pe->SubElements[i],NULL
				).dough;
			vt->push(i,param);
		};

}

//#define evalPE(ret,pe,ext,route) try{return (pe)->Operation->onEvaluate((ret),(pe),(ext));}catch(route &ret)

sRecord funOpXEva(ptrRETNode retnode, ptrParsedElement pe, void* nothing){
	//no information is used.
	//evaluate which to call:
	ptrDough	call=eval(retnode,pe->SubElements[0],NULL).dough;
		//pe->SubElements[0]->Operation->onEvaluate(retnode,pe->SubElements[0],NULL).dough;
	//set new RETNode
	ptrRETNode	nRET=retnode->Append(call);
	//init Params:
	preLocal(nRET,call);
	paramInit(nRET,retnode,call,pe);
	//Execute!:
	try{
		return eval(nRET,(call->ParsedTree),nothing);
	}catch(sRecord& Cast)
	{
		return Cast;
	};
};

ptrOperation loadOpXE(){
	ptrOperation tmp=new cOperation();
	tmp->Name="x()";

	tmp->onEvaluate=funOpXEva;
	tmp->onPreLining=funOpXEPreL;
	tmp->onMakingTree=NULL;
	tmp->onPostLining=NULL;
	tmp->onFoundIdentity=funOpXEFI;
	tmp->Formula="(:higher:|:same:):blank:?\\(:blank:?((:higher:|:lower:|:same:)(:blank:?,:blank:?:higher:|:blank:?,:blank:?:lower:|:blank:?,:blank:?:same:)*)?:blank:?\\)";
	return tmp;
}

#endif